package communication;


import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;



/**
 * Dit is een kanaal voor reeele kanalen die kunnen uitvallen.
 * Wanneer een bericht niet verzonden kan worden wordt die opzij
 * gezet om terug te verzenden wanneer er terug een verbinding is.
 */
public abstract class ReeelKanaalEinde extends KanaalUiteinde {
	private boolean connected = false;
		
	/**
	 * Maakt de eerste verbinding.
	 * 
	 * @throws	KanInitieleVerbindingNietMaken
	 * 			Kan niet verbinden.
	 */
	protected void initVerbinding()
	{
		boolean connected = connect();
		
		if(!connected)
			throw new KanInitieleVerbindingNietMaken();
	}
	
	/**
	 * Geeft aan dat de er succesvol verbonden is.
	 */
	protected void setConnected()
	{
		connected = true;
		
		System.out.println("Connected");
		
		stuurAlleZendBuffer();
	}
	
	/**
	 * Geeft aan dat de verbinding verbroken is.
	 */
	protected void setDisconnected()
	{
		connected = false;
		
		System.out.println("Disconnected");
		
		onDisconnect();
	}
	
	@Override
	public void stuurBericht(byte[] bericht) {
		if(connected)
			try {
				stuurSpecifiek(bericht);
			} catch (IOException e) {
				setDisconnected();
				aanStuurBufferToevoegen(bericht);
			}
		else
		{
			aanStuurBufferToevoegen(bericht);
		}
	}
	
	/**
	 * Stuurt een bericht, specifiek voor het kanaal zonder berichten
	 * te bufferen.
	 * 
	 * @throws	IOException
	 * 			Er is een fout in het verzenden.
	 */
	protected abstract void stuurSpecifiek(byte[] bericht) throws IOException;
	
	/**
	 * Maakt een verbinding en geeft terug of de verbinding succesvol was.
	 */
	protected abstract boolean connect();
	
	/**
	 * Wordt opgeroepen wanneer de verbinden verbroken is.
	 */
	protected abstract void onDisconnect();
	
	/**
	 * Stuurt alle berichten die opzij gezet waren.
	 */
	protected void stuurAlleZendBuffer()
	{
		while(!isStuurBufferLeeg())
		{
			byte[] bytes = popStuur();
		
			stuurBericht(bytes);
		}
	}
	
	protected void aanStuurBufferToevoegen(byte[] bytes)
	{
		stuurBuffer.add(bytes);
	}
	
	protected void aanZendBufferToevoegen(byte[] bytes)
	{
		zendBuffer.add(bytes);
	}
	
	protected byte[] popStuur()
	{
		return stuurBuffer.poll();
	}
	
	protected byte[] popZend()
	{
		return zendBuffer.poll();
	}
	
	protected boolean isZendBufferLeeg()
	{
		return zendBuffer.isEmpty();
	}
	
	protected boolean isStuurBufferLeeg() {
		return stuurBuffer.isEmpty();
	}
	
	private Queue<byte[]> stuurBuffer = new LinkedList<byte[]>();
	private Queue<byte[]> zendBuffer = new LinkedList<byte[]>();
}
